/**
 * File: AbstractStatistic.java
 * Created by: mhaimel
 * Created on: Mar 29, 2010
 * CVS:  $Id: AbstractStatistic.java 1.0 Mar 29, 2010 10:08:52 AM mhaimel Exp $
 */
package uk.ac.ebi.curtain.model.graph.curtain.filter;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.atomic.AtomicReferenceArray;

import org.apache.commons.lang.ObjectUtils.Null;

import uk.ac.ebi.curtain.model.graph.GraphAccess.TouchEach;
import uk.ac.ebi.curtain.model.graph.curtain.StatisticSummary;
import uk.ac.ebi.curtain.utils.StatisticHelper;

/**
 * @author mhaimel
 *
 */
public abstract class AbstractStatistic<T> implements TouchEach<T> {

	private AtomicReferenceArray<LinkedBlockingQueue<Integer>> values;
	
	public AbstractStatistic(Integer categories) {
		this.values  = new AtomicReferenceArray<LinkedBlockingQueue<Integer>>(categories);
		for(int i = 0; i < categories; ++i){
			this.values.set(i, new LinkedBlockingQueue<Integer>());
		}
	}

	@Override
	public void touch(T element) {
		int categories = getCategories();
		for(int cat = 0; cat < categories; ++cat){
			Integer val = getValue(element, cat);
			addValue(cat, val);
		}		
	}

	protected void addValue(int cat, Integer val) {
		if(null != val){
			values.get(cat).add(val);
		}
	}
	
	protected int getCategories(){
		return values.length();
	}
	
	public StatisticSummary<Integer> getStatistic(int cat) {
		return getStatistic(toSortedArray(_values(cat)));
	}

	protected LinkedBlockingQueue<Integer> _values(int cat) {
		return this.values.get(cat);
	}
	
	public StatisticSummary<Integer> getUniqueStatistic(int cat) {
		return getStatistic(toUniqueSortedArray(_values(cat)));
	}
	
	public List<Integer> getSortedArray(Integer cat){
		return toSortedArray(this.values.get(cat));
	}	
	
	public List<Integer> getUniqueSortedArray(Integer cat){
		return toUniqueSortedArray(this.values.get(cat));
	}
	
	protected StatisticSummary<Integer> getStatistic(List<Integer> list) {
		return StatisticHelper.getStatistic(list);
	}

	protected List<Integer> toSortedArray(Collection<Integer> arr) {
		List<Integer> list = new ArrayList<Integer>(arr);
		Collections.sort(list);
		return list;
	}
	
	protected List<Integer> toUniqueSortedArray(Collection<Integer> arr) {
		List<Integer> list = new ArrayList<Integer>(new HashSet<Integer>(arr));
		Collections.sort(list);
		return list;
	}
	
	public void reset() {
		int length = this.values.length();
		for(int i = 0; i < length; ++i){
			_values(i).clear();
		}
	}

	/**
	 * @param element
	 * @param cat
	 * @return Return {@link Null} to ignore value
	 */
	protected abstract Integer getValue(T element, int cat);
	
}
